/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.gaib.dmc;

import static com.gaib.dmc.GaIBReviewer.LoadModel;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import weka.classifiers.Classifier;
import weka.classifiers.UpdateableClassifier;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * @author Ahmad Fauzan
 */
public class GaIBReviewer_Ali implements Reviewer{
    
    final String modelPath = "super.model";
    Classifier cls;
    Instances dataInstances;
    List<Instance> dataSet;
    
    //Atributes
    FastVector atts;
    
    public GaIBReviewer_Ali() {
        cls = LoadModel(modelPath);
        SetUpAttribures(); 
    }

    private void SetUpAttribures() {
        atts = new FastVector();

        String[] atrributeNames = new String[] { "startHour",
            "startWeekday", "duration", "cCount", "cMinPrice", "cMaxPrice",
            "cSumPrice", "bCount", "bMinPrice", "bMaxPrice", "bSumPrice",
            "bStep", "onlineStatus" , "availability" , "maxVal",
            "customerScore","accountLifetime","payments","age","address",
            "lastOrder","order"
        };
        
        // - startHour, startWeekday (Numeric)
        for(int i=0; i < 2 ; i++) {
            atts.addElement(new Attribute(atrributeNames[i]));
        }
        
        // - duration (Nominal)
        String[] attDurationString  =  new String[]{"4.7075","4.7075-16.3865","16.3865-38.7255","38.7255-68.353",
            "68.353-107.079","107.079-147.9045","147.9045-192.652","192.652-241.047","241.047-293.665","293.665-347.768"
                ,"347.768-406.4945","406.4945-467.437","467.437-535.4285","535.4285-606.6895","606.6895-686.96","686.96-776.3395",
                "776.3395-871.841","871.841-981.6175","981.6175-1106.473","1106.473-1247.163","1247.163-1415.6115","1415.6115-1613.371",
                "1613.371-1849.1745","1849.1745-2122.995","2122.995-2464.8075","2464.8075-2925.9085","2925.9085-3586.233","3586.233-4613.249]",
                "4613.249-6921.3","6921.3" };
        FastVector attDurationValue = new FastVector();
        for(int i = 0; i<attDurationString.length ; i++) {
            attDurationValue.addElement(attDurationString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[2], attDurationValue));
        
        // - cCount (Nominal)
        String[] attcCountString = new String[] {"0.5","0.5-1.5","1.5-2.5","2.5-3.5","3.5-4.5","4.5-5.5","5.5-6.5","6.5-7.5","7.5-8.5",
            "8.5-9.5","9.5-10.5","10.5-11.5","11.5-12.5","12.5-13.5", "13.5-14.5", "14.5-15.5","15.5-17.5","17.5-19.5","19.5-21.5","21.5-23.5",
            "23.5-26.5","26.5-29.5","29.5-33.5","33.5-38.5","38.5-44.5","44.5-51.5","51.5-61.5","61.5-76.5","76.5-105.5","105.5"};
        FastVector attcCountValue = new FastVector();
        for(int i =0; i < attcCountString.length; i++) {
            attcCountValue.addElement(attcCountString[i]);
        }
        atts.addElement((new Attribute(atrributeNames[3],attcCountValue)));
        
        // - cMinPrice (Nominal)
        String[] attcMinPriceString = new String[] {"2.97","2.97-3.98","3.98-3.995","3.995-4.995","4.995-6.67","6.67-6.995","6.995-7.98","7.98-8.97",
            "8.97-9.98","9.98-9.995","9.995-12.985","12.985-12.995","12.995-14.995","14.995-17.995","17.995-19.98","19.98-19.995","19.995-24.995",
            "24.995-29.985","29.985-29.995","29.995-39.98","39.98-44.995","44.995-49.995","49.995-69.45","69.45-89.97","89.97-99.995","99.995-199.97",
            "199.97-299.985","299.985-404.99","404.99-604.99","604.99"};
        FastVector attcMinPriceValue = new FastVector();
        for(int i=0; i<attcMinPriceString.length; i++) {
            attcMinPriceValue.addElement(attcMinPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[4], attcMinPriceValue));
        
        // - cMaxPrice (Nominal)
        String[] attcMaxPriceString = new String[] {"6.995","6.995-11.995","11.995-14.995","14.995-19.97","19.97-19.995","19.995-24.98","24.98-24.995",
            "24.995-29.985","29.985-29.995","29.995-35.955","35.955-39.975","39.975-39.995","39.995-49.97","49.97-49.995","49.995-59.955","59.955-59.995",
            "59.995-69.975","69.975-75.97","75.97-79.995","79.995-99.97","99.97-109.475","109.475-139.995","139.995-169.45","169.45-199.995","199.995-299.985",
            "299.985-384.495","384.495-499.995","499.995-600.995","600.995-899.495","899.495"};
        FastVector attcMaxPriceValue = new FastVector();
        for(int i=0; i<attcMaxPriceString.length; i++) {
            attcMaxPriceValue.addElement(attcMaxPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[5],attcMaxPriceValue));
        
        // - cSumPrice
        String[] attcSumPriceString = new String[] {"9.995","9.995-30.975","30.975-47.985","47.985-55.945","55.945-71.925","71.925-89.965","89.965-108.965",
            "108.965-129.925","129.925-149.985","149.985-179.855","179.855-203.845","203.845-239.65","239.65-269.975","269.975-309.79","309.79-359.615",
            "359.615-398.99","398.99-454.895","454.895-526.905","526.905-599.985","599.985-655.685","655.685-761.275","761.275-884.645","884.645-1029.88",
            "1029.88-1211.38","1211.38-1467.33","1467.33-1799.975","1799.975-2362.97","2362.97-3329.925","3329.925-5677.29","5677.29"};
        FastVector attcSumPriceValue = new FastVector();
        for(int i=0; i<attcSumPriceString.length; i++) {
            attcSumPriceValue.addElement(attcSumPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[6],attcSumPriceValue));
        
        // - bCount
        String[] attbCountString = new String[] {"0.5","0.5-1.5","1.5-2.5","2.5-3.5","3.5-4.5","4.5-5.5","5.5-6.5","6.5-7.5","7.5-8.5","8.5-9.5","9.5-10.5","10.5-11.5","11.5-12.5","12.5-13.5","13.5-14.5","14.5-15.5","15.5-16.5","16.5-17.5","17.5-18.5","18.5-19.5","19.5-20.5","20.5-21.5","21.5-22.5","22.5-23.5","23.5-24.5","24.5-25.5","25.5-27.5","27.5-30.5","30.5-36.5","36.5"};
        FastVector attbCountValue = new FastVector();
        for(int i=0; i<attbCountString.length; i++) {
            attbCountValue.addElement(attbCountString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[7],attbCountValue));
        
         // @attribute bMinPrice 
        String[] attbMinPriceString = new String[] {"3.97","3.97-3.995","3.995-5.2","5.2-6.995","6.995-8.195","8.195-9.98","9.98-9.995","9.995-12.985","12.985-12.995","12.995-14.98","14.98-14.995","14.995-17.98","17.98-19.985","19.985-19.995","19.995-24.98","24.98-24.995","24.995-29.985","29.985-29.995","29.995-39.975","39.975-39.995","39.995-49.98","49.98-49.995","49.995-66.47","66.47-89.97","89.97-99.995","99.995-199.97","199.97-299.985","299.985-449.945","449.945-604.99","604.99"};
        FastVector attbMinPriceValue = new FastVector();
        for(int i=0; i<attbMinPriceString.length; i++) {
            attbMinPriceValue.addElement(attbMinPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[8],attbMinPriceValue));
        
        // @attribute bMaxPrice 
         String[] attbMaxPriceString = new String[] {"6.975","6.975-7.995","7.995-9.995","9.995-12.995","12.995-14.995","14.995-17.995","17.995-19.985","19.985-19.995","19.995-24.98","24.98-24.995","24.995-29.985","29.985-29.995","29.995-35.975","35.975-39.975","39.975-39.995","39.995-49.97","49.97-49.995","49.995-59.98","59.98-59.995","59.995-69.995","69.995-79.995","79.995-99.97","99.97-119.995","119.995-167.495","167.495-199.97","199.97-299.985","299.985-399.495","399.495-554.495","554.495-699.495","699.495"};
         FastVector attbMaxPriceValue = new FastVector();
        for(int i=0; i<attbMaxPriceString.length; i++) {
            attbMaxPriceValue.addElement(attbMaxPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[9],attbMaxPriceValue));
        
        // @attribute bSumPrice 
        String[] attbSumPriceString = new String[] {"6.995","6.995-12.975","12.975-16.915","16.915-19.995","19.995-25.095","25.095-29.985","29.985-32.975","32.975-38.985","38.985-39.995","39.995-49.875","49.875-49.995","49.995-59.945","59.945-62.965","62.965-69.985","69.985-79.935","79.935-87.945","87.945-99.895","99.895-108.965","108.965-122.895","122.895-139.985","139.985-160.935","160.935-189.955","189.955-222.905","222.905-270.315","270.315-329.985","329.985-398.985","398.985-512.785","512.785-619.89","619.89-972.365","972.365"};
        FastVector attbSumPriceValue = new FastVector();
        for(int i=0; i<attbSumPriceString.length; i++) {
            attbSumPriceValue.addElement(attbSumPriceString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[10],attbSumPriceValue));
        
        // @attribute bStep 
        String[] attbStepString = new String[] {"null","1","5","2","3","4"};
        FastVector attbStepValue = new FastVector();
        for(int i=0; i<attbStepString.length; i++) {
            attbStepValue.addElement(attbStepString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[11],attbStepValue));
        
        //@attribute onlineStatus 
        String[] attonlineStatusString = new String[] {"y","null","n"};
        FastVector attonlineStatusValue = new FastVector();
        for(int i=0; i<attonlineStatusString.length; i++) {
            attonlineStatusValue.addElement(attonlineStatusString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[12],attonlineStatusValue));
        
        //@attribute availability {'completely orderable','completely not orderable','mainly orderable',mixed,'completely not determinable','mainly not orderable','mainly not determinable'}
        FastVector attValsRel = new FastVector();
        String availabilityString[] = new String[] {
            "completely orderable","completely not orderable",
            "mainly orderable","mixed","mainly not orderable",
            "completely not determinable","mainly not determinable"
        };
        for(int i=0; i < availabilityString.length; i++)
            attValsRel.addElement(availabilityString[i]);
        atts.addElement(new Attribute(atrributeNames[13], attValsRel));
        
        //@attribute maxVal 
        String[] attmaxValString = new String[]{"250","250-350","350-550","550-650","650-750","750-850","850-950","950-1050","1050-1250","1250-1450","1450-1550","1550-1750","1750-2050","2050-2450","2450-2550","2550-2750","2750-2950","2950-3050","3050-3650","3650-3950","3950-4050","4050-4850","4850-4950","4950-5050","5050-7050","7050-8450","8450-8550","8550-10050","10050-13950","13950"};
        FastVector attmaxValValue = new FastVector();
        for(int i=0; i<attmaxValString.length; i++) {
            attmaxValValue.addElement(attmaxValString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[14],attmaxValValue));
        
        //@attribute customerScore numeric
        //@attribute accountLifetime numeric
        //@attribute payments numeric
        for(int i =15; i < 18; i++) {
            atts.addElement(new Attribute(atrributeNames[i]));
        }
        
        //@attribute age 
        String[] attageString = new String[]{"24.5","24.5-27.5","27.5-29.5","29.5-31.5","31.5-33.5","33.5-35.5","35.5-36.5","36.5-37.5","37.5-38.5","38.5-39.5","39.5-40.5","40.5-41.5","41.5-42.5","42.5-43.5","43.5-44.5","44.5-45.5","45.5-46.5","46.5-47.5","47.5-48.5","48.5-49.5","49.5-50.5","50.5-51.5","51.5-52.5","52.5-53.5","53.5-55.5","55.5-57.5","57.5-59.5","59.5-62.5","62.5-67.5","67.5"};
        FastVector attageValue = new FastVector();
        for(int i=0; i<attageString.length; i++) {
            attageValue.addElement(attageString[i]);
        }
        atts.addElement(new Attribute(atrributeNames[18],attageValue));
        
        for(int i =19; i < 21; i++) {
            atts.addElement(new Attribute(atrributeNames[i]));
        }

        // Order (Nominal)
        attValsRel = new FastVector();
        attValsRel.addElement("y");
        attValsRel.addElement("n");
        atts.addElement(new Attribute(atrributeNames[21], attValsRel));
        
        dataInstances = new Instances("DataModel", atts, 280000);
        dataInstances.setClassIndex(dataInstances.numAttributes()-1);
    }
    /**
     * Simple Load Model
     * @param path File Path Model
     * @return
     */
    public static Classifier LoadModel(String path) {
        try {
            InputStream is = GaIBReviewer_Ali.class.getClassLoader().getResourceAsStream(path);
            return (Classifier) weka.core.SerializationHelper.read(is);
        } catch (Exception ex) {
            Logger.getLogger(GaIBReviewer.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
    
    public double submitTransaction(String[] transaction) {
        
        double[] vals = new double[dataInstances.numAttributes()];
        
        // - sessionNo,
        
        // - startHour,startWeekday
        for(int i=0; i < 2 ; i++) {
            if(!transaction[i+1].equals("?")) {
                vals[i] = Double.parseDouble(transaction[i+1]);
                //System.out.println(transaction[i+1] + ":" + vals[i]);
            } else {
                //System.out.println(transaction[i+1] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        // -duration,cCount,
        // - cMinPrice,cMaxPrice,cSumPrice,bCount,bMinPrice,bMaxPrice,bSumPrice(Nominal)
        for(int i=2; i < 11; i++) {
            if(!transaction[i+1].equals("?")) {
                vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i), Double.parseDouble(transaction[i+1]));
                //System.out.println(transaction[i+1] + ":" + vals[i] + ":" + dataInstances.attribute(i).value((int) vals[i]));
            } else {
                //System.out.println(transaction[i+1] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        
        // bStep,onlinestatus (nominal)
        for(int i = 11; i<13; i++) {
            if(!transaction[i+1].equals("?")) {
                vals[i] = dataInstances.attribute(i).indexOfValue(transaction[i+1]);
                //System.out.println(transaction[i+1] + ":" + vals[i]);
            } else {
                //System.out.println(transaction[i+1] + "null");
                vals[i] = dataInstances.attribute(i).indexOfValue("null");
            }
        }
        
        // - availability (Nominal)
        if(!transaction[13].equals("?")) {
            vals[13] = dataInstances.attribute(13).indexOfValue(transaction[14]);
        } else {
            vals[13] = Instance.missingValue();
        }
        // i+2
        // - maxVal
        for(int i=14; i < 15; i++) {
            if(!transaction[i+2].equals("?")) {
                vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i), Double.parseDouble(transaction[i+2]));
                //System.out.println(transaction[i+2] + ":" + vals[i] + ":" + dataInstances.attribute(i).value((int) vals[i]));
            } else {
                //System.out.println(transaction[i+1] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        
        // - customerScore,accountLifetime,
        // - payments
        
        for(int i=15; i < 18 ; i++) {
            if(!transaction[i+2].equals("?")) {
                vals[i] = Double.parseDouble(transaction[i+2]);
                //System.out.println(transaction[i+2] + ":" + vals[i]);
            } else {
                //System.out.println(transaction[i+2] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        
        // - age,address,lastOrder (Numeric)
        for(int i=18; i < 19 ; i++) {
            if(!transaction[i+2].equals("?")) {
                vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i), Double.parseDouble(transaction[i+2]));
                //System.out.println(transaction[i+2] + ":" + vals[i] + ":" + dataInstances.attribute(i).value((int) vals[i]));
            } else {
                //System.out.println(transaction[i+1] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        
        for(int i=19; i < 21 ; i++) {
            if(!transaction[i+2].equals("?")) {
                vals[i] = Double.parseDouble(transaction[i+2]);
                //System.out.println(transaction[i+2] + ":" + vals[i]);
            } else {
                //System.out.println(transaction[i+1] + "Missing Value");
                vals[i] = Instance.missingValue();
            }
        }
        vals[21] = Instance.missingValue();
        
        Instance data = new Instance(1.0, vals);
        dataInstances.add(data);
        data.setDataset(dataInstances);
        dataInstances.add(data);
        
        double classifyDouble=0.5;
         double[] distribution = null;
        try{
            classifyDouble = cls.classifyInstance(data);
            data.setClassValue(classifyDouble);
            distribution = cls.distributionForInstance(data);
            //System.out.println("Clasifying...");
        } catch (Exception ex) {
            //System.out.println(ex.toString());
            Logger.getLogger(GaIBReviewer.class.getName()).log(Level.SEVERE, null, ex);
        }
        if(distribution != null) {
            for(int i=0; i < distribution.length; i++) {
                System.err.println("Double " + i + " : " + distribution[i]);
            }
        }
        
        System.out.println(dataInstances.attribute(dataInstances.numAttributes()-1).value((int)classifyDouble));
       
        
        return (classifyDouble);
    }

    public void submitOutcome(String result) {
        System.out.println(cls.getClass().getName());
        if(cls instanceof UpdateableClassifier) {
            System.out.println("Updateable");
        } else {
            System.out.println("Not Updateable");
        }
    }
    
    /**
     * 
     * @param att Must be atribut involve the range of number
     * @param val
     * @return 
     */
    private double IndexOfRangeInAtribute(Attribute att, double val) {
        double res = 0;
        for(int i=0; i<att.numValues(); i++) {
            String s = att.value(i);
            String[] stemp = s.split("-");
            if(val< Double.parseDouble(stemp[stemp.length-1]))
                break;
            else
                res += 1.0;
        }
        return res;
    }
}
